package com.wrupple.muba.base.client.widgets.reports.pie;

import java.util.List;

import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.hydro4ge.raphaelgwt.client.PathBuilder;
import com.hydro4ge.raphaelgwt.client.Raphael.Path;
import com.hydro4ge.raphaelgwt.client.Raphael.Set;
import com.hydro4ge.raphaelgwt.client.Raphael.Text;
import com.wrupple.muba.base.client.module.domain.RaphaelAttributes;
import com.wrupple.muba.base.client.view.AbstractCanvasCell;
import com.wrupple.muba.base.client.widgets.canvas.DataCanvas;

public abstract class PieChartCell<T> extends AbstractCanvasCell<T> {

	private class MouseOverPieHandler implements MouseOverHandler {
		Path p;
		Text txt;

		public MouseOverPieHandler(Path p, Text txt) {
			super();
			this.p = p;
			this.txt = txt;
		}

		@Override
		public void onMouseOver(MouseOverEvent event) {
			p.animate(focusPathState.getValue(), ms, "elastic");
			txt.animate(focusTextState.getValue(), ms);
		}
	}

	private class MouseOutPieHandler implements MouseOutHandler {
		Path p;
		Text txt;

		public MouseOutPieHandler(Path p, Text txt) {
			super();
			this.p = p;
			this.txt = txt;
		}

		@Override
		public void onMouseOut(MouseOutEvent event) {
			  p.animate(blurPathState.getValue(), ms, "elastic");
		         txt.animate(blurTextState.getValue(), ms);
		}
	}

	protected double rad = Math.PI / 180;
	private List<T> values;
	private Set chart;
	double angle, start;
	int cx, cy, r;
	private String stroke;
	int ms = 500;

	private RaphaelAttributes focusPathState = new RaphaelAttributes();
	private RaphaelAttributes focusTextState = new RaphaelAttributes();
	private RaphaelAttributes blurTextState = new RaphaelAttributes();
	private RaphaelAttributes blurPathState = new RaphaelAttributes();
	private double total;

	public PieChartCell(int cx, int cy, int r, String strokeRgbHexCode) {
		super();
		this.cx = cx;
		this.cy = cy;
		this.r = r;
		this.stroke = strokeRgbHexCode;
		angle = 0;
		start = 0;
		focusPathState.setScale("1.1, 1.1, "+cx+", "+cy);
		
		focusTextState.setOpacity(1);
		
		blurPathState.setScale("1, 1, "+cx+", "+cy);
		
		blurTextState.setOpacity(0);
		
		
	}

	@Override
	public void draw(int index,T value, Object key, DataCanvas<T> canvas) {
		if(chart == null){
			chart = canvas.new Set();
		}
		
		process(value, total, canvas);
	}

	@Override
	public void endDrawing() {
		angle = 0;
		start = 0;
	}
	
	@Override
	public void startDrawing(DataCanvas<T> canvas){
		total = calculatTotalCollectionSumValue(values);
	}

	private void process(T value, double total,  DataCanvas<T> canvas) {
		RaphaelAttributes attributes;
		double numericValue = getNumericValueFor(value);
		double angleplus = 360 * numericValue / total;
		double popangle = angle + (angleplus / 2);
		//String color = "hsb(" + start + ", 1, .5)";
		//String bcolor = "hsb(" + start + ", 1, 1)";
		String bcolor = getColorFor(value);
		int delta = 30;
		
		attributes = new RaphaelAttributes();
		attributes.setFill(bcolor);
		attributes.setStroke(stroke);
		attributes.setStrokeWidth(3);
		Path p = sector(cx, cy, r, angle, angle + angleplus, attributes, canvas);

		Text txt = canvas.new Text(cx + (r + delta + 55) * Math.cos(-popangle * rad), cy + (r + delta + 25)
				* Math.sin(-popangle * rad), getLabelFor(value));
		attributes = new RaphaelAttributes();
		attributes.setFill(bcolor);
		attributes.setStroke(RaphaelAttributes.NONE);
		attributes.setOpacity(0);
		attributes.setFontFamily(RaphaelAttributes.ARIAL_SANS_SERIFF);
		attributes.setFontSize("20px");
		txt.attr(attributes.getValue());
		p.addDomHandler(new MouseOverPieHandler(p, txt), MouseOverEvent.getType());
		p.addDomHandler(new MouseOutPieHandler(p, txt), MouseOutEvent.getType());
		angle += angleplus;
		chart.push(p);
		chart.push(txt);
		start += .1;
	}


	protected Path sector(int cx, int cy, int r, double startAngle, double endAngle, RaphaelAttributes params,  DataCanvas<T> canvas) {
		double x1 = (int) (cx + r * Math.cos(-startAngle * rad));
		double x2 = cx + r * Math.cos(-endAngle * rad);
		double y1 = cy + r * Math.sin(-startAngle * rad);
		double y2 = cy + r * Math.sin(-endAngle * rad);
		PathBuilder builder = new PathBuilder();
		builder.M(cx, cy);
		builder.L(x1, y1);
		builder.A(r, r, 0, (endAngle - startAngle > 180) ? 1 : 0, 0, x2, y2);
		builder.z();
		Path path = canvas.new Path(builder);
		path.attr(params.getValue());
		return path;
	}

	protected abstract String getColorFor(T value);

	protected abstract double getNumericValueFor(T value) ;

	protected abstract String getLabelFor(T value);
	
	protected abstract double calculatTotalCollectionSumValue(List<T> values) ;

}
